﻿using System;
using System.Collections.Generic;

namespace Ruandao.MiniAccess
{

    /// <summary>
    /// 实体类的泛型基类。
    /// </summary>
    /// <typeparam name="T">实体基类的具体实现类。</typeparam>
    /// <remarks>
    /// </remarks>
    public abstract class EntityBase<T> : IEntity where T: EntityBase<T>,new()
    {
        IAccess access;

        /// <summary>
        /// 默认构造，设置实体的状态为EntityStateType.NewCreate。
        /// </summary>
        /// <param name="access">
        /// </param>
        public EntityBase(IAccess access)
        {
            this.access = access;
            this.isNew = true ;
            this.isDelete = false;
            this.oldPropertyValues = new Dictionary<string, object>();
        }
        #region instance member

        #region IEntity 成员

        bool isNew;
        /// <summary>
        /// 
        /// </summary>
        public bool IsNew
        {
            get { return isNew; }
            set { isNew = value; }
        }

        bool isDelete;
        /// <summary>
        /// 
        /// </summary>
        public bool IsDelete
        {
            get { return isDelete; }
            set { isDelete = value; }
        }

        string[] keyPropertyNames = null;
        /// <summary>
        /// 
        /// </summary>
        public string[] KeyPropertyNames
        {
            get
            {
                if (keyPropertyNames == null)
                {
                    keyPropertyNames = access.GetKeyPropertyNames<T>();
                }
                return keyPropertyNames;
            }
        }

        /// <summary>
        /// 保存实体。根据实体的状态，自动选择执行Delete/Update/Insert三个方法之一
        /// <br/>异常：OrMapException(发生SqlException异常，或者没有完成修改和删除的功能。)
        /// </summary>
        public virtual int Save()
        {
            int result = 0;
            if (isNew && (!isDelete))
            {
                result = access.InsertEntity((T)this);
                isNew = false;
            }
            else if  (!isNew)
            {
                if (  KeyPropertyNames.Length==0 )
                {
                    throw new OrMapException("EntityBase基类中的Delete和Update实现不支持无主键的数据表");
                }
                if ( isDelete )
                {
                    result = access.DeleteEntity<T>(OldKeyValues); 
                    isNew = true;
                    oldPropertyValues.Clear();
                }
                else if ( (!isDelete) && oldPropertyValues.Count > 0 )
                {
                    result = access.UpdateEntity<T>((T)this, OldKeyValues);
                    oldPropertyValues.Clear();
                }
            }
            return result;
        }

        #endregion

        IDictionary<string, object> oldPropertyValues;
        /// <summary>
        /// 只读。
        /// </summary>
        IDictionary<string, object> OldPropertyValues
        {
            get
            {
                return this.oldPropertyValues;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="property"></param>
        /// <param name="value"></param>
        protected void ChangePropertyValue(string property, object value)
        {
            if (oldPropertyValues.ContainsKey(property))
            {
                if (oldPropertyValues[property] == value)
                {
                    oldPropertyValues.Remove(property);
                    return;
                }
            }

            // add new item or modify old item.
            oldPropertyValues[property] = value;
        }

        /// <summary>
        /// 得到当前实体的主键参数的原始值集合。
        /// </summary>
        /// <remarks>
        /// 如果属性已经被修改，则原来的值存在OldPropertyValues中，如果没有
        /// 修改则不保存。
        /// 注意：集合的顺序是很重要的，和存储过程中参数顺序一致。
        /// </remarks>
        protected virtual object[] OldKeyValues
        {
            get
            {
                string[] names = KeyPropertyNames;
                object[] values = new object[names.Length];

                Type t = typeof(T);
                for (int i = 0; i < names.Length; i++)
                {
                    if ( oldPropertyValues.ContainsKey(names[i]) )
                    {
                        values[i] = oldPropertyValues[names[i]];
                    }
                    else
                    {
                        values[i] = t.GetProperty(names[i]).GetValue(this, null);
                    }
                }
                return values;
            }
        }

        #endregion

    }
}
